import pandas as pd
import numpy as np
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
import seaborn as sns
import networkx as nx
import warnings
import math
%matplotlib inline
warnings.filterwarnings('ignore')
from collections import Counter
Dieser Plot zeigt das ganze Netzwerk als ungerichteter Graph auf. Die Nodegrösse wird anhand der Betweenness Zentralität bestimmt.
Analyse: Alle Nodes, welche aussen platziert sind und keine Verbindung (roter Strich) zu einem anderen Node haben, visualisieren die Häfen, welche keine Fahrten zu anderen Häfen haben. Das können zum Beispiel Fischerhäfen sein. In der Mitte der Grafik sind die Häfen abgebildet, welche am meisten Verbindungen zu anderen Nodes haben. Grundlegend kann gesagt werden, dass rund die Hälfte aller Häfen nur mit sich oder mit einzelnen anderen Nodes verknüpft sind. Die andere Hälfte dagegen haben Verbindungen zu mehreren anderen Häfen, wobei auch viele der stark verbundenen Häfen eine hohe Betweenness-Zentralität haben.
#define nodes
arrival_nodes = df.ArrivalPort.tolist()
departure_nodes = df.DeparturePort.tolist()
nodes = set(np.concatenate((arrival_nodes, departure_nodes)))
#define edges
edges = []
for i in df.index:
edge = (df['DeparturePort'][i], df['ArrivalPort'][i])
edges.append(edge)
node_nr = len(nodes)
edge_nr = len(edges)
print("Das gesamte Netzwerk weist", node_nr, "Nodes und", edge_nr, "Edges auf. Die Nodes repräsentieren die Häfen und Edges sind die Fahrten zwischen zwei Häfen.")
#create undirected Graph
graph_undirected = nx.Graph()
graph_undirected.add_nodes_from(nodes)
graph_undirected.add_edges_from(edges)
#calculate betweeness-cantrality
betweenness_centrality = nx.betweenness_centrality(graph_undirected, k=None, normalized=False, weight=None, endpoints=False, seed=None)
#plot whole network
pos=nx.spring_layout(graph_undirected)
plt.figure(1, figsize=(45,45))
nx.draw(graph_undirected,pos,node_color='#A0CBE2', edges=edges, edge_color='#BB0000',width=1,node_size=[math.log(v+2)*50 for v in betweenness_centrality.values()],font_size=5,with_labels=False)
plt.show()
Dieser Plot zeigt das ganze Netzwerk als gerichteter Graph auf. Die Dicke der roten Linie zeigt das Gewicht der Kante an.
Analyse: Im Gegensatz zum ungerichteten Graphen werden Pfeile angezeigt, welche die Fahrtrichtung der Schiffe visualisieren. Je zentraler ein Hafen ist, desto höher ist die Wahrscheinlichkeit, dass die Schiffe in beide Richtungen verkehren. Das gilt auch für das Gewicht der Kanten. Es ist auch erkennbar, dass Schiffe von eher zentralen Häfen nur in eine Richtung zu Häfen fahren, welche aussen positioniert sind. Dass können zum Beispiel Insel-Häfen sein, welche hauptsächlich Waren importieren und nichts exportieren, oder solche Häfen, welche nur als Zwischenstopp dienen. Bei Verbindungs-Häfen mit einem hohen Gewicht kann es sich um Passagierschiffe oder Fähren handeln, welche mehrere Mal pro Stunde Hin- und zurück fahren.
#create directed graph with weights
graph_directed = nx.DiGraph((x, y, {'weight': v}) for (x,y), v in Counter(edges).items())
graph_directed.add_nodes_from(nodes)
graph_directed.add_edges_from(edges)
#graph.edges(data = True)
#plot whole network. Without labels
pos=nx.spring_layout(graph_directed)
plt.figure(1, figsize=(45,45))
weights = [graph_directed[u][v]['weight']*0.003 for u,v in edges]
nx.draw(graph_directed,pos,node_color='#A0CBE2',edge_color='#BB0000',width=weights,node_size=100,font_size=5,with_labels = False)
plt.show()
Dieser Plot zeigt das ganze Netzwerk als gerichteter Graph auf. Zusätzlich werden die Labels der Häfen angezeigt, welche einen höheren gewichteten Degree als 50 haben.
Analyse: Es wurden nur die Labels der Häfen angezeigt, welche einen hohen gewichteten Degree aufweisen. Sonst wäre der Graph schlicht zu überfüllt und unübersichtlich. Sehr auffällig ist nun, dass die Nodes der stark gewichtete Kanten oft nicht beschriftet sind, was bedeutet, dass diese nicht sehr viele Verbindungen zu anderen Nodes haben. So wird die oben gestellte Hypothese bestätigt, dass solche Verbindungen hauptsächlich von Passagierschiffen oder Fähren befahren werden, welche in einem kleinen Intervall Hin- und zurückfahren. Im Zentrum des Graphs ist ein Cluster von holländischen Häfen wie Rotterdam und Amsterdam zu sehen. Diese Verbindungen führen wahrscheinlich alle durch den Ärmelkanal.
#plot whole network. Ports with most traffic labeled
pos=nx.spring_layout(graph_directed, k = 0.2)
plt.figure(1, figsize=(45,45))
weights = [graph_directed[u][v]['weight']*0.003 for u,v in edges]
weighted_degrees = []
labels = {}
for n in nodes:
weighted_degree = 0
for e in graph_directed.edges(n, data = True):
weighted_degree += e[2].get('weight')
weighted_degrees.append((n,weighted_degree))
if (weighted_degree > 50):
labels[n] = n
nx.draw(graph_directed,pos,node_color='#A0CBE2',edge_color='#BB0000',width=weights,node_size=180,font_size=5,with_labels = False)
nx.draw_networkx_labels(graph_directed,pos,labels,font_size=12,font_color='black')
plt.show()